package cc.flyflow.core.listeners;

import cc.flyflow.common.dto.process.ProcessInstanceExecutionDto;
import cc.flyflow.core.node.NodeDataStoreFactory;
import cc.flyflow.core.utils.BizHttpUtil;
import cc.flyflow.core.utils.FlowableUtils;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.log.StaticLog;
import cc.flyflow.common.dto.process.ProcessInstanceNodeRecordParamDto;
import cc.flyflow.common.dto.flow.Node;
import cc.flyflow.common.utils.JsonUtil;
import org.flowable.common.engine.api.delegate.event.FlowableEvent;
import org.flowable.engine.RuntimeService;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.util.Map;

import static cc.flyflow.common.constants.ProcessInstanceConstant.VariableKey.NODE_JUMP_KEY;
import static cc.flyflow.common.constants.ProcessInstanceConstant.VariableKey.REDIS_KEY_OF_FLOW_UNIQUE_ID;

/**
 * 节点单个条件处理器 监听策略
 * <p>
 * 事件侦听器策略
 *
 * @author Jyl
 */
public interface EventListenerStrategy
{

    /**
     * 策略注册方法
     *
     * @param key
     */
    default void afterPropertiesSet(String key)
    {
        EventListenerStrategyFactory.register(key, this);
    }

    /**
     * 处理数据
     *
     * @param event
     * @return
     */
    void handle(FlowableEvent event);

    /**
     * 保存开始事件内容
     *
     * @param flowId            流程id
     * @param processInstanceId 流程实例id
     * @param activityId        活动Id
     * @param activityName      活动名称
     * @param executionId       执行Id
     * @param tenantId          租户id
     * @param parentExecutionId 父执行Id
     */
    default void saveStartEventContent(
            String flowId,
            String processInstanceId,
            String activityId,
            String activityName,
            String executionId,
            String tenantId,
            String parentExecutionId)
    {
        //获取Flowable 运行实例
        RuntimeService runtimeService = SpringUtil.getBean(RuntimeService.class);
        Map<String, Object> processVariables = runtimeService.getVariables(executionId);

        Node node = NodeDataStoreFactory.getInstance().getNode(flowId, activityId, tenantId);
        String parentNodeId = MapUtil.getStr(processVariables, StrUtil.format(NODE_JUMP_KEY, activityId));

        ProcessInstanceNodeRecordParamDto nodeRecordParamDto = new ProcessInstanceNodeRecordParamDto();

        nodeRecordParamDto.setFlowId(flowId);
        nodeRecordParamDto.setProcessInstanceId(processInstanceId);
        nodeRecordParamDto.setData(JsonUtil.toJSONString(processVariables));
        nodeRecordParamDto.setNodeId(activityId);
        nodeRecordParamDto.setParentNodeId(parentNodeId);

        RedisTemplate redisTemplate = SpringUtil.getBean("redisTemplate", RedisTemplate.class);
        if (StrUtil.isNotBlank(parentNodeId))
        {
            //跳转过来的
            String s = IdUtil.fastSimpleUUID();
            ZSetOperations zSetOperations = redisTemplate.opsForZSet();

            String key = StrUtil.format(REDIS_KEY_OF_FLOW_UNIQUE_ID, processInstanceId);
            String value = StrUtil.format("{}||||{}", activityId, s);

            zSetOperations.add(key, value, System.currentTimeMillis());

            nodeRecordParamDto.setFlowUniqueId(s);
        } else
        {
            String flowUniqueId = FlowableUtils.getFlowUniqueId(activityId, flowId,
                    processInstanceId, tenantId);
            nodeRecordParamDto.setFlowUniqueId(flowUniqueId);
        }

        if (node != null)
        {
            nodeRecordParamDto.setNodeType((node.getType()));
        }
        nodeRecordParamDto.setNodeName(activityName);
        nodeRecordParamDto.setExecutionId(executionId);
        nodeRecordParamDto.setTenantId(tenantId);
        BizHttpUtil.startNodeEvent(nodeRecordParamDto);

        //保存执行信息
        ProcessInstanceExecutionDto executionDto = new ProcessInstanceExecutionDto();

        executionDto.setExecutionId(executionId);
        executionDto.setParentIdExecutionId(parentExecutionId);
        executionDto.setProcessInstanceId(processInstanceId);
        executionDto.setNodeId(activityId);
        executionDto.setTenantId(tenantId);

        executionDto.setFlowId(flowId);
        BizHttpUtil.saveExecution(executionDto);

        StaticLog.info("节点开始了： {} {}  {} ", flowId, executionId, activityName);

        //清除变量
        runtimeService.removeVariable(executionId, StrUtil.format(NODE_JUMP_KEY, activityId));
    }
}
